package com.baikeyang.service.activity.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import com.baikeyang.common.bean.ResponseResult;
import com.baikeyang.common.constant.CommonConstants;
import com.baikeyang.common.constant.ExecuteConstants;
import com.baikeyang.common.constant.QiniuConstants;
import com.baikeyang.common.model.ActivityFileLibrary;
import com.baikeyang.common.model.ActivityPhotoAlbumFile;
import com.baikeyang.common.util.StringUtils;
import com.baikeyang.common.util.shiro.ShiroUtil;
import com.baikeyang.mapper.ActivityFileLibraryMapper;
import com.baikeyang.mapper.ActivityPhotoAlbumFileMapper;
import com.baikeyang.service.WxUser.IWxUserService;
import com.baikeyang.service.activity.IActivityFileLibraryService;
import com.baikeyang.service.base.impl.SuperServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
//import com.google.gson.Gson;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.channels.FileChannel;
import java.util.*;

/**
 * <p>
 * 活动媒体文件库 服务实现类
 * </p>
 *
 * @author BaiKeyang
 * @since 2019-05-15
 */
@Service
public class ActivityFileLibraryServiceImpl extends SuperServiceImpl<ActivityFileLibraryMapper, ActivityFileLibrary> implements IActivityFileLibraryService {

	@Autowired
	private ActivityFileLibraryMapper fileLibraryMapper;

	@Autowired
	private ActivityPhotoAlbumFileMapper albumFileMapper;

	@Override
	public IPage<ActivityFileLibrary> loadActivityFilePage(Page<ActivityFileLibrary> pageParam) {
		QueryWrapper<ActivityFileLibrary> wr = new QueryWrapper<ActivityFileLibrary>();
		wr.orderByDesc("CREATE_TIME");
		return fileLibraryMapper.selectPage(pageParam, wr);
	}

	@Override
	public ResponseResult saveFile(MultipartFile multipartFile, String tempFileName, String fileName, Integer size, String type, Date lastModifiedDate,
								Integer chunks, Integer chunk, String md5, String album, HttpServletRequest request) throws IOException {
		// 上传目录：如果上传目录不存在，则创建该目录
		String uploadPath = request.getServletContext().getRealPath( QiniuConstants.getUploadDirPath() );
		// 将文件上传到磁盘
		File file = uploadFileToDisk(uploadPath, multipartFile, tempFileName, fileName, chunks, chunk, md5);
		if(null != chunks && null != chunk){// 分片上传
			// 判断是否为最后一次
			if(chunk == chunks-1 && null != file){
				file = mergeUpload(uploadPath, md5, fileName);
			}else{
				file = null;
			}
		}

		if(null != file){// 将上传后磁盘上的完整文件到上传到云存储服务
			String key = uploadFileToCloudDisk(file);
			ActivityFileLibrary fileLibrary = new ActivityFileLibrary();
			fileLibrary.setFileName(fileName);
			fileLibrary.setFileSize(Long.parseLong(size.toString()));// 文件大小
			fileLibrary.setFileSuffix(type);// 文件类型/后缀
			fileLibrary.setFilePath(file.getPath());// 文件绝对路径(文件所在磁盘路径)
			fileLibrary.setFileNeturl("http://image.bkybk.com/"+key);// 文件云存储路径
			fileLibrary.setFileMd5(md5);// 文件唯一指纹
			fileLibrary.setCreateTime(new Date());
			fileLibrary.setCreateUser(ShiroUtil.getCurrentUserId());
			fileLibrary.setUpdateTime(new Date());
			fileLibrary.setUpdateUser(ShiroUtil.getCurrentUserId());
			Integer flag = fileLibraryMapper.insert(fileLibrary);
			if (flag > 0) {
				if(StringUtils.isNotEmpty(album)){
					ActivityPhotoAlbumFile apaf = new ActivityPhotoAlbumFile();
					apaf.setFileId(fileLibrary.getId());
					apaf.setAlbumId(Integer.parseInt(album));
					albumFileMapper.insert(apaf);
				}
				return new ResponseResult(ExecuteConstants.EXECUTESTATUS.成功, ExecuteConstants.EXECUTEINFO.成功, ExecuteConstants.EXECUTECODE.CODE_200, fileLibrary.getFileNeturl());
			}
			return new ResponseResult(ExecuteConstants.EXECUTEINFO.失败, ExecuteConstants.EXECUTECODE.CODE_403);
		}else{
			//if(chunk == chunks-1){// 分片上传成功，继续处理下一个分片文件
				return new ResponseResult(ExecuteConstants.EXECUTESTATUS.成功, ExecuteConstants.EXECUTEINFO.成功, ExecuteConstants.EXECUTECODE.CODE_200);
		//	}
		}
		//return new ResponseResult(ExecuteConstants.EXECUTEINFO.失败, ExecuteConstants.EXECUTECODE.CODE_202);
	}

	private File uploadFileToDisk (String uploadPath, MultipartFile multipartFile, String tempFileName,
								   String fileName, Integer chunks, Integer chunk, String md5) {
		try {

			File up = new File( uploadPath );
			if ( !up.exists() ) {
				up.mkdir();
			}

			File file = null;
			if(null != chunks && null != chunk){// 分片上传

				String directoryName = tempFileName+"_"+fileName;
				if(StringUtils.isNotEmpty(md5)){ directoryName = md5; }

				// 创建文件目录
				File dir = new File( uploadPath+File.separator+directoryName+File.separator);
				if(!dir.exists()){// 如果目录不存在则创建
					dir.mkdirs();
				}

				// 创建分片文件
				file = new File( uploadPath+File.separator+directoryName+File.separator+chunk);
				// 内存图片写入磁盘
				multipartFile.transferTo(file);

			} else {// 整体上传

				// 创建文件
				file = new File( uploadPath+File.separator+fileName);
				if(file.exists()){// 如果文件存在，则删除
					file.delete();
				}

				multipartFile.transferTo(file);

			}
			return file;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	public String uploadFileToCloudDisk(File file) throws QiniuException {
		return uploadFileToCloudDisk(file, null);
	}

	private String uploadFileToCloudDisk(File file, String rename) throws QiniuException {
		Auth auth = Auth.create(QiniuConstants.getAccessKey(), QiniuConstants.getSecretKey());
		//Auth auth = Auth.create("DIoJ0oXEoczT6BJXMhnp-9CESvatRMjtu8TlEtI0", "KXtQie6CIoaRB11I6QAiMg3t9C8BIfrv44dRoVAw");

//		StringMap stringMap = new StringMap();
//		String fileId = "20923";
//		StringMap putPolicy = new StringMap();
//		putPolicy.put("returnBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\"," +
//			"\"fsize\":$(fsize),\"fileId\":\"$(x:fileId)\"}");
//		long expireSeconds = 3600;
//		String upToken = auth.uploadToken(QiniuConstants.getBucket(), null, expireSeconds, putPolicy);

		String upToken = auth.uploadToken(QiniuConstants.getBucket());
		//String upToken = auth.uploadToken("youthbucket");
		Configuration configuration = new Configuration(Zone.autoZone());
		UploadManager manager = new UploadManager(configuration);

		//默认不指定key的情况下，以文件内容的hash值作为文件名
		String key = null, hash = null;
		if(StringUtils.isNotEmpty(rename)){
			key = rename;
		}

		Response response = manager.put(file, key, upToken);
		//解析上传成功的结果
		DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
		key = putRet.key;
		hash = putRet.hash;
		return key;
	}

	/**
	 * 合并上传目录文件
	 * @param path 目录位置
	 * @param resourcesDirectory 源目录
	 * @param target 目标文件
	 */
	private static File mergeUpload(String path, String resourcesDirectory,String target) throws IOException {

		// 1、先找到源目录下的所有被合并文件
		File f = new File( path + File.separator + resourcesDirectory);
		File[] fileArray = f.listFiles(new FileFilter() {
			// 排除目录，只要文件
			public boolean accept(File pathname) {
				if (pathname.isDirectory()) {
					return false;
				}
				return true;
			}
		});
		if(null != fileArray && fileArray.length > 0){
			// 转成集合，便于排序
			List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));
			// 按照分片的顺序排
			Collections.sort(fileList, new Comparator<File>() {
				public int compare(File o1, File o2) {
					if (Integer.parseInt(o1.getName()) < Integer.parseInt(o2.getName())) {
						return -1;
					}
					return 1;
				}
			});

			// 2、创建合并文件
			File file = new File(path + File.separator + target);
			file.createNewFile();
			// 获取输出流
			FileChannel outChannel  = new FileOutputStream(file).getChannel();

			// 3、开始合并
			FileChannel inChannel;
			for (File tmp : fileList) {
				inChannel = new FileInputStream(tmp).getChannel();
				inChannel.transferTo(0, inChannel.size(), outChannel);
				inChannel.close();
				// 删除分片
				tmp.delete();
			}
			if (outChannel != null) {
				// 清除临时文件
				deleteFile(f);
				// 关闭流
				outChannel.close();
			}
			return file;
		}else{
			System.out.println("没有需要合并的文件");
		}
		return null;
	}

	/**
	 * 递归删除文件夹
	 * @param file
	 * @return
	 */
	private static boolean deleteFile(File file) {
		if(file==null||!file.exists()){

			return true;
		}
		if (file.isDirectory()) {
			String[] children = file.list();//递归删除目录中的子目录下
			for (int i=0; i<children.length; i++) {
				boolean success = deleteFile(new File(file, children[i]));
				if (!success) {
					return false;
				}
			}
		}
		// 目录此时为空，可以删除
		return file.delete();
	}

	@Override
	public ResponseResult deleteFile(String id) {
		if(StringUtils.isNotEmpty(id)){
			ActivityFileLibrary fileLibrary = fileLibraryMapper.selectById(id);
			if (null != fileLibrary) {
				fileLibrary.setState(CommonConstants.DATA_STATUS_DELETE);
				int flag = fileLibraryMapper.updateById(fileLibrary);
				if (flag > 0) {
					return new ResponseResult(ExecuteConstants.EXECUTESTATUS.成功, ExecuteConstants.EXECUTEINFO.成功, ExecuteConstants.EXECUTECODE.CODE_200);
				}
			}
		}
		return new ResponseResult(ExecuteConstants.EXECUTEINFO.失败, ExecuteConstants.EXECUTECODE.CODE_403);
	}

	@Override
	public ResponseResult checkFile(String md5) {
		if(StringUtils.isNotEmpty(md5)){
			QueryWrapper<ActivityFileLibrary> wr = new QueryWrapper<ActivityFileLibrary>();
			wr.eq("FILE_MD5", md5);
			List<ActivityFileLibrary> activityFileLibraries = fileLibraryMapper.selectList(wr);
			boolean resultFlag = false;
			if(CollectionUtil.isNotEmpty(activityFileLibraries)){// 已存在
				resultFlag = true;
			}
			return new ResponseResult(ExecuteConstants.EXECUTESTATUS.成功, ExecuteConstants.EXECUTEINFO.成功, ExecuteConstants.EXECUTECODE.CODE_200, resultFlag);
		}
		return new ResponseResult(ExecuteConstants.EXECUTEINFO.失败, ExecuteConstants.EXECUTECODE.CODE_403);
	}

	@Override
	public ResponseResult checkChunk(String md5, Integer chunk, Integer chunkSize, HttpServletRequest request) {
		if (StringUtils.isNotEmpty(md5) && null != chunk && null != chunkSize) {
			// 上传目录：如果上传目录不存在，则创建该目录
			String uploadPath = request.getServletContext().getRealPath( QiniuConstants.getUploadDirPath() );
			String filePath = uploadPath+File.separator+md5+File.separator+chunk;//合并文件必须要按照顺序合并，所以不能重命名
			File file = new File(filePath);
			long length = file.length();
			boolean resultFlag = false;
			if(file.exists()&&length==chunkSize){//分片已存在，这里一定要验证传过来的分片大小是否和已存在的分片大小相同，
				resultFlag = true;
			}
			return new ResponseResult(ExecuteConstants.EXECUTESTATUS.成功, ExecuteConstants.EXECUTEINFO.成功, ExecuteConstants.EXECUTECODE.CODE_200, resultFlag);
		}
		return new ResponseResult(ExecuteConstants.EXECUTEINFO.失败, ExecuteConstants.EXECUTECODE.CODE_403);
	}

	@Override
	public List<ActivityFileLibrary> loadActivityFileLibraryByAlbum(int album) {
		QueryWrapper<ActivityPhotoAlbumFile> queryWrapper = new QueryWrapper<ActivityPhotoAlbumFile>();
		queryWrapper.eq("ALBUM_ID", album);
		List<ActivityPhotoAlbumFile> activityPhotoAlbumFiles = albumFileMapper.selectList(queryWrapper);
		List<Integer> files = new ArrayList<>();
		if(!CollectionUtils.isEmpty(activityPhotoAlbumFiles)){
			for(ActivityPhotoAlbumFile albumFile : activityPhotoAlbumFiles){
				files.add(albumFile.getFileId());
			}

		}
		QueryWrapper<ActivityFileLibrary> wr = new QueryWrapper<ActivityFileLibrary>();
		wr.in("ID", files);
		return fileLibraryMapper.selectList(wr);
	}

	@Override
	public ResponseResult fileUpdateForWx(MultipartFile multipartFile, String userId, HttpServletRequest request) {
		try {
			// 上传目录：如果上传目录不存在，则创建该目录
			String uploadPath = request.getServletContext().getRealPath( QiniuConstants.getUploadDirPath() );
			String fileName = multipartFile.getOriginalFilename();
			// 将文件上传到磁盘
			File file = uploadFileToDisk(uploadPath, multipartFile, null, fileName, null, null, null);
			if(null != file){// 将上传后磁盘上的完整文件到上传到云存储服务
				String key = uploadFileToCloudDisk(file);
				System.out.println(FileUtil.getType(file));
				ActivityFileLibrary fileLibrary = new ActivityFileLibrary();
				fileLibrary.setFileName(fileName);
				fileLibrary.setFileSize(FileUtil.size(file));// 文件大小
				fileLibrary.setFileSuffix(FileUtil.extName(file));// 文件类型/后缀
				fileLibrary.setFilePath(file.getPath());// 文件绝对路径(文件所在磁盘路径)
				fileLibrary.setFileNeturl("http://image.bkybk.com/"+key);// 文件云存储路径
				fileLibrary.setFileMd5("");// 文件唯一指纹
				fileLibrary.setCreateTime(new Date());
				fileLibrary.setCreateUser(Long.parseLong(userId));
				fileLibrary.setUpdateTime(new Date());
				fileLibrary.setUpdateUser(Long.parseLong(userId));
				Integer flag = fileLibraryMapper.insert(fileLibrary);
				if (flag > 0) {
					return new ResponseResult(ExecuteConstants.EXECUTESTATUS.成功, ExecuteConstants.EXECUTEINFO.成功, ExecuteConstants.EXECUTECODE.CODE_200, fileLibrary.getFileNeturl());
				}
				return new ResponseResult(ExecuteConstants.EXECUTEINFO.失败, ExecuteConstants.EXECUTECODE.CODE_403);
			}else{
				//if(chunk == chunks-1){// 分片上传成功，继续处理下一个分片文件
				return new ResponseResult(ExecuteConstants.EXECUTESTATUS.成功, ExecuteConstants.EXECUTEINFO.成功, ExecuteConstants.EXECUTECODE.CODE_200);
				//	}
			}
		} catch (QiniuException e) {
			e.printStackTrace();
		}

		return null;
	}

	public static void main(String[] args) {
		try {
			ActivityFileLibraryServiceImpl fileLibraryService = new ActivityFileLibraryServiceImpl();
			File f = new File("E:\\log\\IMG_1343.JPG");
			String key = fileLibraryService.uploadFileToCloudDisk(f, "");
			System.out.println(key);
		} catch (QiniuException e) {
			e.printStackTrace();
		}

	}
}
